use crate::osWaitForever;

use super::EventFlags;
use alloc::collections::vec_deque::VecDeque;
use critical_section::with;
use utils::MutCell;

pub struct MessageQueue<T> {
    queue: MutCell<VecDeque<T>>,
    event_flags: EventFlags,
}

const FLAG_NOTIFY: u32 = 0x01;

impl<T: Send + 'static> MessageQueue<T> {

    pub fn new() -> Self {
        Self {
            queue: MutCell::const_new(VecDeque::new()),
            event_flags: EventFlags::new("message queue"),
        }
    }

    pub fn post(&self, value: T) {
        with(|_| {
            let queue = unsafe { self.queue.as_mut() };
            queue.push_back(value);
        });
        self.event_flags.set_flags(FLAG_NOTIFY);
    }

    pub fn poll(&self, timeout: u32) -> Option<T> {
        let mut flag = false;
        loop {
            let ret = with(|_| unsafe { self.queue.as_mut() }.pop_front() );
            if flag || ret.is_some() {
                return ret;
            }
            flag = true;
            _ = self.event_flags.wait_any_flags(FLAG_NOTIFY, timeout);
        }
    }

    pub fn take(&self) -> T {
        
        loop {
            let ret = with(|_| {
                let queue = unsafe { self.queue.as_mut() };
                queue.pop_front()
            });
            if let Some(ret) = ret {
                return ret;
            }
            _ = self.event_flags.wait_any_flags(FLAG_NOTIFY, osWaitForever);
        }
    }
}
